package ge;

import java.util.BitSet;
import java.util.HashMap;
import java.util.List;

import ec.BitSolution;
import ec.Solution;
import ge.standardsymbols.StartSymbol;

public class GESolution extends BitSolution implements Iterable<Integer> {

	private static final boolean use_pruning = true;
	
	protected GESolution() {
		super();
		
		_info.put("num_codons", 0);
		_info.put("num_used_codons", 0);
		
		ALLOW_VARIABLE_LENGTH_CROSSOVER = true;
	}

	public GESolution(int num_codons, double bit_mutation_rate) {
		this(num_codons, 8, bit_mutation_rate);
		
		ALLOW_VARIABLE_LENGTH_CROSSOVER = true;
	}

	public GESolution(int num_codons, int codon_length, double bit_mutation_rate) {
		super(num_codons, codon_length, bit_mutation_rate);
		
		ALLOW_VARIABLE_LENGTH_CROSSOVER = true;
		
		_info.put("num_codons", num_codons);
		_info.put("num_used_codons", num_codons);

	}

	public int getNumCodons() {
		return _num_blocks;
	}
	
	@Override
	protected GESolution createEmptySolution() {
		return new GESolution();
	}

	public List<Solution> crossover(Solution solutionB) {
		List<Solution> offspring = super.crossover(solutionB);
		
		if (use_pruning){
			for (Solution child : offspring) {
				((GESolution) child).prune();
			}
		}
		
		return offspring;
	}

	public GESolution mutate() {
		GESolution mutant = duplicate();

		super.mutate(mutant);
		
		if (use_pruning) {			
			mutant.prune();
		}
		
		return mutant;
	}
	
	public GESolution duplicate() {
		return (GESolution) super.duplicate(new GESolution());
	}

	public CodonIterator iterator() {
		return new CodonIterator(this);
	}

	public void prune() {
		CodonIterator iter = iterator();
		Expression exp = StartSymbol.resolve(iter);
		int last_index = iter.getNumCalls();
		int num_codons = getNumCodons();
		
		if (last_index < num_codons) {
			int old_length = _bits.size();
			int new_length = last_index * _block_length;
			BitSet pruned = new BitSet(new_length);
			for (int i = 0; i < new_length; i++) {
				pruned.set(i, _bits.get(i));
			}
			
			_num_blocks = last_index;
			_info.put("num_codons", last_index);
			_info.put("num_used_codons", last_index);

			_bits = pruned;
			
		}
	}

}
